package hedron;

import static hedron.i18n.Internationalization._;
import hedron.db.ContactsManager;
import hedron.db.DBManager;
import hedron.db.IDManager;
import hedron.db.StockManager;
import hedron.db.StoreManager;
import hedron.db.model.User;
import hedron.dialog.LoginDialog;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
/**
 * This class controls all aspects of the application's execution. Used also as
 * singletons container.
 */
public class Application implements IApplication {
	public static final String CORE_DB_HOST = "core.db.host";
	public static final String CORE_LANGUAGE = "core.language";
	public static final String CORE_DATE_FORMAT = "core.date.format";

	public static final Logger log = Logger.getLogger("HEDRON");
	protected static IStatusLineManager statusLine;
	public static final DBManager DB;
	public static final IDManager ID;
	public static final ContactsManager CONTACTS;
	public static final StockManager STOCKS;
	public static final StoreManager STORES;

	static final Properties properties = new Properties();
	static String currentDirectory;
	private final static SimpleDateFormat simpleDateFormater = new SimpleDateFormat();

	private static User currentUser;

	// initialize the singletons container
	static {
		try {
			currentDirectory = (new File(".").getCanonicalPath());
		} catch (IOException e1) {
			currentDirectory = ".";
			e1.printStackTrace();
		}

		// initialize logger
		log.setUseParentHandlers(false);
		{
			Formatter logFormater = new LogFormatter();
			Handler conHdlr;

			conHdlr = new ConsoleHandler();
			conHdlr.setFormatter(logFormater);
			log.addHandler(conHdlr);
			try {
				conHdlr = new FileHandler(currentDirectory + "/hedron.log", false);
				conHdlr.setFormatter(logFormater);
				log.addHandler(conHdlr);
			} catch (Exception e) {
				log.log(Level.WARNING, "Cannot initialoze Logger file", (Throwable) e);
			}
		}

		// current directory
		log.info("Working directory is: " + currentDirectory);

		// loading properties
		try {
			File file = new File("HEDRON.properties");
			if (file.exists()) {
				properties.load(new FileInputStream(file));
			}
		} catch (Exception e) {
			log.log(Level.WARNING, "Cannot load property file", e);
		}

		// date format
		String dateFormat = "yyyy-MM-dd";
		if (properties != null) {
			dateFormat = properties.getProperty(CORE_DATE_FORMAT, dateFormat);
		}
		try {
			simpleDateFormater.applyPattern(dateFormat);
		} catch (Exception e) {
			simpleDateFormater.applyPattern("yyyy-MM-dd");
		}

		// load localization
		_("");

		// initialize Managers
		// DB Manager must be first
		DB = DBManager.instance;
		ID = new IDManager(DB);
		CONTACTS = new ContactsManager(ID, DB);
		STOCKS = new StockManager(ID, DB);
		STORES = new StoreManager(ID, DB);
	}

	public Object start(IApplicationContext context) throws Exception {
		Display display = PlatformUI.createDisplay();
		Display.setAppName(_("Application.Name"));

		/*{
			Shell shell = new Shell(display);

			LoginDialog dialog = new LoginDialog(shell);
			dialog.create();
			if (dialog.open() != Window.OK) {
				return IApplication.EXIT_OK;
			}
		}*/

		try {
			int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
			if (returnCode == PlatformUI.RETURN_RESTART) return IApplication.EXIT_RESTART;
		} catch (Throwable e) {
			e.printStackTrace();
		} finally {
			display.dispose();
			dispose();
		}
		return IApplication.EXIT_OK;
	}

	private void dispose() {
		if (DB != null) {
			DB.dispose();
		}
		log.info("Hedron Store Management closed");
	}

	public void stop() {

		final IWorkbench workbench = PlatformUI.getWorkbench();
		if (workbench == null) return;
		final Display display = workbench.getDisplay();
		display.syncExec(new Runnable() {
			public void run() {
				if (!display.isDisposed()) workbench.close();
			}
		});
	}

	public static final void setStatusMessage(int errorLevel, String message) {
		if (statusLine != null) {
			Image statusImage;
			if (errorLevel == 1) {
				statusImage = JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_WARNING);
			} else if (errorLevel == 2) {
				statusImage = JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_ERROR);
			} else {
				statusImage = JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_INFO);
			}
			JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_ERROR);
			statusLine.setMessage(statusImage, message);
		}
	}

	public final static IWorkbenchWindow getActiveWorkbench() {
		return PlatformUI.getWorkbench().getActiveWorkbenchWindow();
	}

	public final static IWorkbenchPage getActivePage() {
		return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
	}

	public static String getProperty(String key) {
		return properties.getProperty(key);
	}

	public static String getProperty(String key, String defaultValue) {
		return properties.getProperty(key, defaultValue);
	}

	public static class LogFormatter extends Formatter {
		private final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss - ");

		@Override
		public String format(LogRecord record) {
			StringBuilder result = new StringBuilder();
			result.append(dateFormat.format(new Date(record.getMillis())));
			result.append(record.getLevel());
			result.append(": [");
			result.append(record.getSourceClassName());
			result.append(".");
			result.append(record.getSourceMethodName());
			result.append("] ");
			result.append(record.getMessage());
			result.append('\n');
			Throwable throwable = record.getThrown();
			if (throwable != null) {
				printThrown(result, throwable);
				result.append('\n');
			}
			return result.toString();
		}

		private void printThrown(StringBuilder result, Throwable thrown) {

			result.append("").append(thrown.getClass().getName());
			result.append(" - ").append(thrown.getMessage());
			result.append("\n");

			for (StackTraceElement trace : thrown.getStackTrace())
				result.append("\tat ").append(trace).append("\n");

			Throwable cause = thrown.getCause();
			if (cause != null) {
				result.append("\n");
				printThrown(result, cause);
			}
		}
	}

	public static void placeDialogInCenter(Shell parent, Shell shell) {
		if (shell != null) {
			Rectangle parentSize = (parent != null) ? parent.getBounds() : shell.getDisplay().getBounds();
			Rectangle mySize = shell.getBounds();

			int locationX, locationY;
			locationX = ((parentSize.width - mySize.width) >> 1) + parentSize.x;
			locationY = ((parentSize.height - mySize.height) >> 1) + parentSize.y;

			shell.setLocation(new Point(locationX, locationY));
		}
	}

	public static String formatDate(Date date) {
		if (date != null) {
			return simpleDateFormater.format(date);
		} else {
			return "";
		}
	}

	/**
	 * Escape \ and '
	 */
	static String escape(String value) {
		StringBuilder result = new StringBuilder();
		for (int i = 0, len = value.length(); i < len; i++) {
			char c = value.charAt(i);
			if ((c == '\\') || (c == '\'')) {
				result.append('\\');
			}
			result.append(c);
		}
		return result.toString();
	}

	public static long getCurrentUserID() {
		return currentUser.getID();
	}

	public static User getCurrentUser() {
		return currentUser;
	}

	public static boolean authenticateUserPass(String username, String password) {
		boolean result = false;
		Connection conn = DB.getConnection();
		if (conn != null) {
			try {
				ResultSet rs = DB.query(conn, "SELECT * FROM huser WHERE UCASE(U_NAME) = UCASE(?) AND U_PASS = ? ",
						username, password);

				if (rs != null && DB.next(rs)) {
					currentUser =  new User(rs);
					result = true;
				}else{
					currentUser = null;
				}
				DB.close(rs);
			} finally {
				DB.closeConnection(conn);
			}
		}
		return result;
	}
}
